package ${packageName!''}.service.impl;

import ${packageName!''}.dto.PageInfo;
import ${packageName!''}.dto.Pageable;
import ${packageName!''}.entity.${beanClassName!''};
import ${packageName!''}.entity.${beanClassName!''}Example;
import ${packageName!''}.entity.SysUser;
import ${packageName!''}.exception.BusinessException;
import ${packageName!''}.mapper.${beanClassName!''}Mapper;
import ${packageName!''}.service.${beanClassName!''}Service;
import com.github.pagehelper.PageHelper;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.*;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
* ${name!''}-业务实现类
*/
@CacheConfig(cacheNames = "${beanClassName!''}")//设置缓存名称
@Service
public class ${beanClassName!''}ServiceImpl implements ${beanClassName!''}Service {
    @Autowired
    ${beanClassName!''}Mapper ${beanName!''}Mapper;

    /**
     * 分页查询
     * @param pageable 查询参数封装类实体
     * @return
     */
    @Cacheable(key="'getPage_'+#pageable.toString()")//缓存结果,
    // 指定自定义key生成策略{@link ${packageName!''}.config.redis.RedisConfig}
    // 一般用于查询操作，根据key查询缓存，如果key不存在，查询db，并将结果更新到缓存中，如果key存在，直接查询缓存中的数据。
    public PageInfo<${beanClassName!''}> getPage(Pageable pageable){
        ${beanClassName!''}Example example = new ${beanClassName!''}Example();
        ${beanClassName!''}Example.Criteria criteria = null;
        if (pageable==null)
            pageable = new Pageable();
        else
            criteria = example.createCriteria();
        PageHelper.startPage(pageable);
        if (!StringUtils.isEmpty(pageable.getStrVal()))
            criteria.andCodeLike(pageable.getStrVal()+"%");
        if (!StringUtils.isEmpty(pageable.getStrVal1()))
            criteria.andNameLike(pageable.getStrVal1()+"%");
        List<${beanClassName!''}> list = ${beanName!''}Mapper.selectByExample(example);
        return new PageInfo<${beanClassName!''}>(list);
    }

    @Cacheable(key = "'id_'+#id")//缓存结果，以id_[实际id]为key
    public ${beanClassName!''} getById(Long id){
        return ${beanName!''}Mapper.selectByPrimaryKey(id);
    }

    @CacheEvict(key = "'regex:getPage_*'")
    //保存数据后删除getPage方法上的缓存数据，这里使用了正则匹配的方式
    public ${beanClassName!''} save(${beanClassName!''} ${beanName!''}) {
        if (${beanName!''}==null)
            throw  new BusinessException("${beanName!''}为null");
        //数据字段校验
        check(${beanName!''},false);
        //设置操作人、操作时间、操作人IP信息
        setOperator(${beanName!''});
        ${beanName!''}Mapper.insert(${beanName!''});//返回行数，但对象的id会自动赋值上去
        return ${beanName!''}Mapper.selectByPrimaryKey(${beanName!''}.getId());
    }

    @Caching(
            put = {
                    @CachePut(key = "'id_' + #${beanName!''}.id")//数据更新后，更新缓存key为id_[实际id]的数据
            }
            ,evict = {
                //更新数据后删除getPage方法上的缓存数据，这里使用了正则匹配的方式
                @CacheEvict(key = "'regex:getPage_*'")
            }
    )
    @Override
    public ${beanClassName!''} update(${beanClassName!''} ${beanName!''}) {
        //数据字段校验
        check(${beanName!''},true);
        //设置操作人、操作时间、操作人IP信息
        setOperator(${beanName!''});
        //只更新值不为null的字段
        int rows = ${beanName!''}Mapper.updateByPrimaryKeySelective(${beanName!''});
        if (rows>1)
            throw new BusinessException("更新失败，存在多个主键为"+${beanName!''}.getId()+"的记录！");
        return ${beanName!''}Mapper.selectByPrimaryKey(${beanName!''}.getId());
    }

    @Caching(evict = {
            //删除数据后删除getPage方法上的缓存数据，这里使用了正则匹配的方式
            @CacheEvict(key = "'getPage_*'"),
            //删除数据后删除key为id_[实际id]的缓存
            @CacheEvict(key = "'id_' + #${beanName!''}.id")
    }
    )
    @Override
    public boolean delete(Long id) {
        int rows = ${beanName!''}Mapper.deleteByPrimaryKey(id);
        if (rows>1)
            throw new BusinessException("删除失败，存在多个主键为"+id+"的记录！");
        return rows==1;
    }

    /**
     * 根据主键批量删除
     * 如果当前操作表关联其他业务表，不建议使用此方法，而应该使用deleteBatch_方法
     * @param ids
     * @return
     */
    @CacheEvict(allEntries = true)//删除数据后,清空所有缓存名称为${beanClassName!''}的所有数据
    @Override
    public int deleteBatch(Long[] ids) {
        ${beanClassName!''}Example example = new ${beanClassName!''}Example();
        example.createCriteria().andIdIn(Arrays.asList(ids));
        int rows = ${beanName!''}Mapper.deleteByExample(example);
        return rows;
    }

    /**
     * 根据主键批量删除
     * @param ids
     * @return
     */
    @CacheEvict(allEntries = true)//删除数据后,清空所有缓存名称为${beanClassName!''}的所有数据
    @Override
    public int deleteBatch_(Long[] ids) {
        int rows = 0;
        for (Long id : ids) {
            int row = ${beanName!''}Mapper.deleteByPrimaryKey(id);
            rows += row;
            if (row==1) {
                //TODO 这里写删除后的其他操作
            }
        }
        return rows;
    }

    /**
     * 更新、新增前数据检查（非空、唯一性等）
     * @param ${beanName!''}
     */
    @Override
     public void check(${beanClassName!''} ${beanName!''}, boolean isUpdate) throws BusinessException{
        if (StringUtils.isEmpty(${beanName!''}.getName()))
            throw new BusinessException("名称不能为空");
        if (StringUtils.isEmpty(${beanName!''}.getCode()))
            throw new BusinessException("编码不能为空");
        ${beanClassName!''}Example example = new ${beanClassName!''}Example();
        example.createCriteria().andCodeEqualTo(${beanName!''}.getCode()).andCodeIsNotNull();
        long temp = isUpdate?1:0;
        long count = ${beanName!''}Mapper.countByExample(example);
        if (count!=temp)
            throw new BusinessException("编码【"+${beanName!''}.getCode()+"】已存在");
        example.clear();
        example.createCriteria().andNameEqualTo(${beanName!''}.getName()).andNameIsNotNull();
        count = ${beanName!''}Mapper.countByExample(example);
        if (count!=temp)
            throw new BusinessException("名称【"+${beanName!''}.getName()+"】已存在");
    }

    /**
     * 更新或新增时设置操作人信息
     * @param ${beanName!''}
     */
    private void setOperator(${beanClassName!''} ${beanName!''}){
        Subject subject = SecurityUtils.getSubject();
        SysUser loginUser = (SysUser) subject.getPrincipal();
        ${beanName!''}.setOperator(String.format("%s[%s]",loginUser.getUsername(),loginUser.getRealname()));
        ${beanName!''}.setOperateTime(new Date());
        ${beanName!''}.setOperateIp(loginUser.getLoginIp());
    }
}
